#include "cameramanager.h"

CameraManager::CameraManager()
{
    eyeVector.x=WORLD_XSIZE/2;
    eyeVector.y=WORLD_YSIZE/4;
    eyeVector.z=WORLD_ZSIZE-10;
    rotx=roty=0;
}

void CameraManager::GetCurrentFrustrum(){
       float   proj[16];
       float   modl[16];
       float   clip[16];
       float   t;

       /* Get the current PROJECTION matrix from OpenGL */
       glGetFloatv( GL_PROJECTION_MATRIX, proj );

       /* Get the current MODELVIEW matrix from OpenGL */
       glGetFloatv( GL_MODELVIEW_MATRIX, modl );

       /* Combine the two matrices (multiply projection by modelview) */
       clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12];
       clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13];
       clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14];
       clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15];

       clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12];
       clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13];
       clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14];
       clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15];

       clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12];
       clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13];
       clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14];
       clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15];

       clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12];
       clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13];
       clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14];
       clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15];

       /* Extract the numbers for the RIGHT plane */
       frustum[0][0] = clip[ 3] - clip[ 0];
       frustum[0][1] = clip[ 7] - clip[ 4];
       frustum[0][2] = clip[11] - clip[ 8];
       frustum[0][3] = clip[15] - clip[12];

       /* Normalize the result */
       t = sqrt( frustum[0][0] * frustum[0][0] + frustum[0][1] * frustum[0][1] + frustum[0][2] * frustum[0][2] );
       frustum[0][0] /= t;
       frustum[0][1] /= t;
       frustum[0][2] /= t;
       frustum[0][3] /= t;

       /* Extract the numbers for the LEFT plane */
       frustum[1][0] = clip[ 3] + clip[ 0];
       frustum[1][1] = clip[ 7] + clip[ 4];
       frustum[1][2] = clip[11] + clip[ 8];
       frustum[1][3] = clip[15] + clip[12];

       /* Normalize the result */
       t = sqrt( frustum[1][0] * frustum[1][0] + frustum[1][1] * frustum[1][1] + frustum[1][2] * frustum[1][2] );
       frustum[1][0] /= t;
       frustum[1][1] /= t;
       frustum[1][2] /= t;
       frustum[1][3] /= t;

       /* Extract the BOTTOM plane */
       frustum[2][0] = clip[ 3] + clip[ 1];
       frustum[2][1] = clip[ 7] + clip[ 5];
       frustum[2][2] = clip[11] + clip[ 9];
       frustum[2][3] = clip[15] + clip[13];

       /* Normalize the result */
       t = sqrt( frustum[2][0] * frustum[2][0] + frustum[2][1] * frustum[2][1] + frustum[2][2] * frustum[2][2] );
       frustum[2][0] /= t;
       frustum[2][1] /= t;
       frustum[2][2] /= t;
       frustum[2][3] /= t;

       /* Extract the TOP plane */
       frustum[3][0] = clip[ 3] - clip[ 1];
       frustum[3][1] = clip[ 7] - clip[ 5];
       frustum[3][2] = clip[11] - clip[ 9];
       frustum[3][3] = clip[15] - clip[13];


       /* Normalize the result */
       t = sqrt( frustum[3][0] * frustum[3][0] + frustum[3][1] * frustum[3][1] + frustum[3][2] * frustum[3][2] );
       frustum[3][0] /= t;
       frustum[3][1] /= t;
       frustum[3][2] /= t;
       frustum[3][3] /= t;

       /* Extract the FAR plane */
       frustum[4][0] = clip[ 3] - clip[ 2];
       frustum[4][1] = clip[ 7] - clip[ 6];
       frustum[4][2] = clip[11] - clip[10];
       frustum[4][3] = clip[15] - clip[14];

       /* Normalize the result */
       t = sqrt( frustum[4][0] * frustum[4][0] + frustum[4][1] * frustum[4][1] + frustum[4][2] * frustum[4][2] );
       frustum[4][0] /= t;
       frustum[4][1] /= t;
       frustum[4][2] /= t;
       frustum[4][3] /= t;

       /* Extract the NEAR plane */
       frustum[5][0] = clip[ 3] + clip[ 2];
       frustum[5][1] = clip[ 7] + clip[ 6];
       frustum[5][2] = clip[11] + clip[10];
       frustum[5][3] = clip[15] + clip[14];

       /* Normalize the result */
       t = sqrt( frustum[5][0] * frustum[5][0] + frustum[5][1] * frustum[5][1] + frustum[5][2] * frustum[5][2] );
       frustum[5][0] /= t;
       frustum[5][1] /= t;
       frustum[5][2] /= t;
       frustum[5][3] /= t;

       lookAtVector = vector3<float>(frustum[5][0],frustum[5][1],frustum[5][2]);
       upVector = vector3<float>(frustum[2][0],frustum[2][1],frustum[2][2]);
       strideVector = lookAtVector.cross(upVector).unit();
}

bool CameraManager::PtInFrustrum(float x, float y, float z){
    int p;

       for( p = 0; p < 6; p++ )
          if( frustum[p][0] * x + frustum[p][1] * y + frustum[p][2] * z + frustum[p][3] <= FRUSTRUM_CULL_THRESHOLD )
              return false;

       return true;
}

bool CameraManager::ChunkInFrustrum(Chunk& c){
    int x=c.worldX();
    int y=c.worldY();
    int z=c.worldZ();
    if(!PtInFrustrum(x,y,z) &&
       !PtInFrustrum(x+CHUNK_SIZE-1,y,z) &&
       !PtInFrustrum(x+CHUNK_SIZE-1,y+CHUNK_SIZE-1,z) &&
       !PtInFrustrum(x+CHUNK_SIZE-1,y+CHUNK_SIZE-1,z+CHUNK_SIZE-1) &&
       !PtInFrustrum(x,y+CHUNK_SIZE-1,z+CHUNK_SIZE-1) &&
       !PtInFrustrum(x,y,z+CHUNK_SIZE-1)&&
       !PtInFrustrum(x,y+CHUNK_SIZE-1,z))return false;
    return true;
}

vector3<float>& CameraManager::getLookAtVector(){
  return lookAtVector;
}

void CameraManager::panLeft(float amt){
    rotx-=amt;
}

void CameraManager::panRight(float amt){
    rotx+=amt;
}

void CameraManager::panUp(float amt){
    roty-=amt;
}

void CameraManager::panDown(float amt){
    roty+=amt;
}

void CameraManager::goLeft(float amt){

    eyeVector-=strideVector*amt;
}

void CameraManager::goRight(float amt){

    eyeVector+=strideVector*amt;
}

void CameraManager::goUp(float amt){
    eyeVector-=upVector*amt;
}

void CameraManager::goDown(float amt){
    eyeVector+=upVector*amt;
}

void CameraManager::goForward(float amt){
    eyeVector+=(lookAtVector * amt);
}

void CameraManager::goBack(float amt){
    eyeVector-=(lookAtVector * amt);
}

float CameraManager::getEyeX(){
    return eyeVector.x;
}

float CameraManager::getEyeY(){
    return eyeVector.y;
}

float CameraManager::getEyeZ(){
    return eyeVector.z;
}

float CameraManager::getRotY(){
    return roty;
}

float CameraManager::getRotX(){
    return rotx;
}

vector3<float>& CameraManager::getEyeVector(){
    return eyeVector;
}

vector3<float>& CameraManager::getUpVector(){
    return upVector;
}

vector3<float> &CameraManager::getStrideVector(){
    return strideVector;
}
//finish it
void CameraManager::lookAt(vector3<float> center, float dist){
    eyeVector = center - (lookAtVector * dist);
}

void CameraManager::reset(){
    eyeVector.x=WORLD_XSIZE/2;
    eyeVector.y=WORLD_YSIZE/4;
    eyeVector.z=WORLD_ZSIZE-10;
    rotx=0;
    roty=0;
}


